package nz.ac.vuw.ecs.kcassell.anonymous;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * This class has no fields. It has some methods that store and retrieve objects
 * from files and some that store and retrieve from databases.
 * @author Keith Cassell
 */
public class AnonymousPersistence {

	public void saveSerializableToFile(Object obj, String file) {
		FileOutputStream foStream = null;
		ObjectOutputStream ooStream = null;
		try {
			foStream = new FileOutputStream(file);
			ooStream = new ObjectOutputStream(foStream);
			ooStream.writeObject(obj);
			ooStream.close();
		} catch (IOException e) {
			handleSerializationException("Unable to write to " + file, e);
		}
	}

	public static Object readSerializableFromFile(String file) {
		Object obj = null;
		FileInputStream fis = null;
		ObjectInputStream ois = null;
		try {
			fis = new FileInputStream(file);
			ois = new ObjectInputStream(fis);
			obj = (Object) ois.readObject();
			ois.close();
		} catch (IOException e) {
			handleSerializationException("Unable to read from " + file, e);
		} catch (ClassNotFoundException e) {
			handleSerializationException("", e);
		}
		return obj;
	}

	protected static void handleSerializationException(String msg, Exception e) {
		System.err.println(msg + ": " + e);
		e.printStackTrace();
	}

	public Object readFromDB() {
		Object obj = null;
		String url = "org.somewhere.Driver";
		loadDriver(url);
		Connection connection = null;
		Statement statement = null;
		ResultSet resultSet = null;
		try {
			connection = DriverManager.getConnection(url);
			statement = connection.createStatement();
			resultSet = getDatabaseValues(statement);
			// TODO reconstruction via reflection
			resultSet.close();
		} catch (SQLException sqle) {
			handleSQLException(sqle);
		} finally {
			releaseResources(connection, statement, resultSet);
		}
		return obj;
	}

	public void saveToDB(Object obj) {
		String url = "org.apache.derby.jdbc.ClientDriver";
		loadDriver(url);
		Connection connection = null;
		PreparedStatement statement = null;
		try {
			connection = DriverManager.getConnection(url);
			// TODO populate tables using values obtained from reflection
			String sqlString = "INSERT CLASS_TABLE VALUES (?, ?)";
			statement = connection.prepareStatement(sqlString);
			saveDatabaseValues(obj, statement);
		} catch (SQLException sqle) {
			handleSQLException(sqle);
		} finally {
			releaseResources(connection, statement, null);
		}
	}

	public void loadDriver(String driver) {
		try {
			Class.forName(driver).newInstance();
		} catch (Exception e) {
			System.err.println("Unable to load the JDBC driver " + driver);
		}
	}

	private ResultSet getDatabaseValues(Statement statement)
			throws SQLException {
		ResultSet resultSet;
		String sqlString = "SELECT * FROM CLASS_TABLE";
		resultSet = statement.executeQuery(sqlString);
		return resultSet;
	}

	private void saveDatabaseValues(Object obj, PreparedStatement statement)
			throws SQLException {
		statement.setString(1, obj.getClass().getSimpleName());
		statement.setString(2, obj.getClass().getPackage().getName());
		statement.executeUpdate();
	}

	public static void handleSQLException(SQLException e) {
		while (e != null) {
			System.err.println("\n----- SQLException: " + e.getMessage());
			System.err.println("  Error Code: " + e.getErrorCode());
			e.printStackTrace(System.err);
			e = e.getNextException();
		}
	}

	public void releaseResources(Connection conn, Statement statement,
			ResultSet result) {
		try {
			if (result != null) result.close();
			if (statement != null) statement.close();
			if (conn != null) conn.close();
		} catch (SQLException sqle) {
			handleSQLException(sqle);
		}
	}

}
